package util.wcl
{
	import mx.formatters.DateFormatter;
	
	public class DateUtil
	{
		public static const MILLI_IN_DAY:Number 	= 24*60*60*1000;
		public static const MILLI_IN_HOUR:Number 	= 60*60*1000;
		public static const MILLI_IN_MINUTE:Number 	= 60*1000;
		public static const MILLI_IN_SECOND:Number 	= 60*1000;
		private static var tmp:Date = new Date();

		[Bindable]
		public static var defaultFormat:String	= "YYYY-MM-DD";
		public static var basicFormat:String = "YYYYMMDD";
		public static var dotFormat:String = "YYYY.MM.DD";
		public static var basicTimeFormat:String = "JJNNSS";
		public static var MMDDFormat:String = "MM.DD";
		public static var YYYYMMFormat:String = "YYYYMM";
		public static var timeFormat:String = "JJ:NN"
		public static var millisecondsOfaDay:Number = 3600*1000*24;
		
		private static var dateFormatter:DateFormatter = new DateFormatter();
		
//shgoo 2010.01.18		
		public static function toFormatString(src:Date, format:String):String {
			dateFormatter.formatString = format;
			return dateFormatter.format(src);
		}
///////////////

		public static function stringToDateTime(src:String):Date
		{
			if(src == null || src == "") {
				return null;
			}
			var items:Array = src.split(" ");
			var dateElements:Array = items[0].split("-");  
			var timeElements:Array = items[1].split(":");
			if(dateElements[1]>0) {
				dateElements[1] --;
			}  
			return new Date(dateElements[0], dateElements[1], dateElements[2], timeElements[0], timeElements[1], timeElements[2]);  			
		}
		
		public static function toBasicString(src:Date):String
		{
			dateFormatter.formatString = DateUtil.basicFormat;
			return dateFormatter.format(src);
		}
		
		public static function toDotString(src:Date):String
		{
			dateFormatter.formatString = DateUtil.dotFormat;
			return dateFormatter.format(src);
		}
		
		public static function toBasicTimeString(src:Date):String{
			dateFormatter.formatString = DateUtil.basicTimeFormat;
			return dateFormatter.format(src);
			
		}

		public static function toDefaultString(src:Date):String
		{
			dateFormatter.formatString = DateUtil.defaultFormat;
			return dateFormatter.format(src);
		}
		
		public static function toMMDDString(src:Date):String
		{
			dateFormatter.formatString = DateUtil.MMDDFormat;
			return dateFormatter.format(src);
		}

		public static function toYYYYMMString(src:Date):String
		{
			dateFormatter.formatString = DateUtil.YYYYMMFormat;
			return dateFormatter.format(src);
		}

		public static function toTimeString(src:Date):String
		{
			dateFormatter.formatString = timeFormat;
			return dateFormatter.format(src);
		}
		
		public static function today():String
		{
			var date:Date = new Date();
			dateFormatter.formatString = defaultFormat;
			return dateFormatter.format(date);
		}
		
		public static function todayNoTime():Date
		{
			var date:Date = new Date();
			date.hours = date.minutes = date.seconds = date.milliseconds = 0;
			return date;
		}
		
		public static function thisYear():int
		{
			var date:Date = new Date();
			return date.fullYear;
		}
		
		public static function firstDateOfMonth(date:Date):Date
		{
			var tmp:Date = new Date(date);
			tmp.date = 1;
			return tmp;
		}
		
		public static function firstDateofThisMonth():Date
		{
			var date:Date = new Date();
			date.date = 1;
			return date;
		}
		
		public static function firstDateofThisYear():Date
		{
			var date:Date = new Date();
			date.month = 0;
			date.date = 1;
			return date;
		}

		public static function lastDateofThisYear():Date
		{
			var date:Date = new Date();
			date.month = 11;
			date.date = 31;
			return date;
		}

		public static function lastDateOfMonth(date:Date):Date
		{
			var tmp:Date = new Date(date);
			tmp.month++;
			tmp.date = 1;
			tmp.date--;
			return tmp;
		}
		
		public static function lastDateOfThisMonth():Date
		{
			var tmp:Date = new Date();
			tmp.month++;
			tmp.date = 1;
			tmp.date--;
			return tmp;
		}
		
		public static function getAfterDayExcepted(src:Date, days:int):Date
		{
			var tmp:Date = new Date(src);
			for(var i:int=0; i<days-1; tmp.date ++) {
				if(tmp.day != 0 && tmp.day != 6) {
					i++
				}
			}	
			return tmp;		
		}
		
		public static function getAfterDay(src:Date, days:int):Date
		{
			var tmp:Date = new Date(src);
			tmp.date += days;
			return tmp;		
		}
		
		public static function DateDiff(fromDate:Date, toDate:Date):Number
		{
			fromDate.hours = fromDate.minutes = fromDate.milliseconds = 0;
			toDate.hours = toDate.minutes = toDate.milliseconds = 0;
         	return Math.abs((Number(toDate) - Number(fromDate)) / (millisecondsOfaDay) + 1);
   		}
   		
 		public static function DateDiff2(fromDate:Date, toDate:Date, holidays:Array=null):int
		{
			var sdt:Date = new Date(fromDate);
			var edt:Date = new Date(toDate);
			sdt.hours = sdt.minutes = sdt.milliseconds = 0;
			edt.hours = edt.minutes = edt.milliseconds = 0;
			
			var tempDiff:int = (Number(edt) - Number(sdt)) / (millisecondsOfaDay);
			var returnVal:int = tempDiff
			if(returnVal<0) {
				returnVal-=1;
				for(var i:int = 0; i >= tempDiff; i--)
				{
					if(sdt.day == 0 || sdt.day == 6)
					{
						returnVal += 1;
					}
					sdt.date -= 1; 
	    		}
			}
			else {
				returnVal+=1;
				for(var j:int = 0; j <= tempDiff; j++)
				{
					if(sdt.day == 0 || sdt.day == 6)
					{
						returnVal -= 1;
					}
					sdt.date += 1; 
	    		}
	 	 	}
 		
  	 		if(holidays!=null) {
	 			for each(var holi:Date in holidays) {
	 				if(Number(holi)>=Number(fromDate) && Number(holi)<=Number(toDate)) {
	 					returnVal-=1;
	 				} 
	 			}
	 		}
 			return returnVal;
   		}

   		public static function hourDiff(beginTime:Date, endTime:Date):Number
   		{
   			return Math.abs((beginTime.hours+(beginTime.minutes/60))-(endTime.hours+(endTime.minutes/60)));
   		}
   		public static function hourDiff2(beginTime:Date, endTime:Date):Number	// 초과근무 시간계산
   		{
   			var retVal:Number;
   			if(beginTime.hours > endTime.hours) {
   				var tmp:Number = 24 - (beginTime.hours+(beginTime.minutes/60));
   				retVal =(endTime.hours+(endTime.minutes/60)) + (24 - (beginTime.hours+(beginTime.minutes/60)));
   			}
   			else {
   				retVal =(endTime.hours+(endTime.minutes/60)) - (beginTime.hours+(beginTime.minutes/60));
   			}
   			return  Math.floor(retVal*10)/10;;
   		}
   		
   		public static function sameDate(b:Date, e:Date):Boolean
   		{
			return (b.fullYear==e.fullYear && b.month==e.month && b.date==e.date);			
   		}




		public static function hasTime(date:Date):Boolean
		{
			return date.milliseconds == date.seconds == date.minutes == date.hours == 0;
		}

		public static function daysInMonth(date:Date):int
		{
			tmp.setTime(date.getTime());
			tmp.date = 1;
			tmp.month++;
			tmp.date -= 1;			
			return tmp.date;
		}
		public static function firstDayOfMonth(date:Date):int
		{
			tmp.setTime(date.getTime());
			tmp.date = 1;
			return tmp.day;
		}
		public static function startOfMonth(date:Date):Date
		{
			var result:Date = new Date(date.getTime());
			result.date = 1;
			result.seconds = result.minutes = result.milliseconds = result.hours = 0;
			return result;
		}

		public static function endOfMonth(date:Date,advanceMidnight:Boolean = false):Date
		{
			var result:Date = new Date(date.getTime());
			result.date = 1;
			result.seconds = result.minutes = result.milliseconds = result.hours = 0;
			result.month += 1;
			result.milliseconds -= 1;
			return result;
		}

		public static function startOfWeek(date:Date):Date
		{
			var result:Date = new Date(date);
			result.date -= result.day;
			result.seconds = result.minutes = result.milliseconds = result.hours = 0;
			return result;
		}
		public static function endOfWeek(date:Date,advanceMidnight:Boolean = false):Date
		{
			var result:Date = startOfWeek(date);
			result.date += 6; 
			return result;
		}
		
		public static function startOfDay(date:Date):Date
		{
			var result:Date = new Date(date.getTime());
			result.seconds = result.minutes = result.milliseconds = result.hours = 0;
			return result;
		}

		public static function endOfDay(date:Date,advanceMidnight:Boolean = false):Date
		{
			var result:Date = new Date(date.getTime());
			result.seconds = result.minutes = result.milliseconds = result.hours = 0;
			result.date = result.date + 1;
			result.milliseconds -= 1;
			return result;
		}
		public static function toHours(value:Date):Number
		{
			return toDays(value)*24 + value.hours + value.minutes /60 + value.seconds/(60*60);
		}
		
		public static function timeOnly(date:Date):Number
		{
			return date.hours * MILLI_IN_HOUR + date.minutes * MILLI_IN_MINUTE + date.seconds * MILLI_IN_SECOND + date.milliseconds;
		}

		public static function toDays(value:Date):Number
		{
			var dayCount:Number = 0;
			for(var year:Number = value.fullYear-1;year >= 1970;year--)
			{
				if((year & 0x3) == 0)
					dayCount += 366;
				else
					dayCount += 365;
			}
			for(var month:Number = value.month-1;month >= 0;month--)
			{
				dayCount += DAYS_IN_MONTH[month];
				if(month == 1 && ((value.fullYear & 0x3) == 0)) {
					dayCount += 1;
				}
			}
			dayCount += value.date - 1;
			
			
			return dayCount;
		}
		public static function rangeDaySpan(r:DateRange):Number
		{
			return daySpan(r.start,r.end);
		}
		public static function daySpan(fromValue:Date,toValue:Date):Number
		{
			return toDays(toValue) - toDays(fromValue) + 1;
		}

		public static function rangeWeekSpan(r:DateRange):Number		
		{
			return weekSpan(r.start,r.end);
		}
		
		public static function weekSpan(start:Date,end:Date):Number
		{
			var sow:Date = startOfWeek(start);
			var range:Number = (end.getTime() - sow.getTime()) / MILLI_IN_DAY;
			// this is a bit of a hack, to deal with leapyear. This could theoreticall still fail.
			// the right way to deal would be to see if the range spans a non-leapyear, and adjust by the appropriate number of milliseconds
			// before dividing.			
			if(hasTime(start) == false && hasTime(end) == false)
				range = Math.round(range);
			return Math.ceil((range)/7);
		}
		
		public static function expandRangeToDays(r:DateRange,expandMidnight:Boolean = false):void
		{
			r.start = startOfDay(r.start);
			r.end = endOfDay(r.end,expandMidnight);			
		}
		public static function expandRangeToWeeks(r:DateRange,expandMidnight:Boolean = false):void
		{
			r.start = startOfWeek(r.start);
			r.end = endOfWeek(r.end,expandMidnight);
		}
		public static function expandRangeToMonths(r:DateRange,expandMidnight:Boolean = false):void
		{
			r.start = startOfMonth(r.start);
			r.end = endOfMonth(r.end,expandMidnight);
		}
		
		public static function isHoliday(target:Date, holidays:Array):Boolean
		{
			if(target.day==0 || target.day==6) return true;
			for each( var h:Date in holidays) {
				if(h.fullYear==target.fullYear && h.month==target.month && h.date==target.date) return true;
			}
			return false;			
		}


		// 0321 반영 안함. 
		// 년도를 받아서 해당년의 첫날과 끝날을 구함
		public function firstDateofThisYear(yyyy:int):Date
		{
			var date:Date = new Date();
			date.fullYear = yyyy;
			date.month = 0;
			date.date = 1;
			return date;
		}

		public function lastDateofThisYear(yyyy:int):Date
		{
			var date:Date = new Date();
			date.fullYear = yyyy;
			date.month = 11;
			date.date = 31;
			return date;
		}
				
		private static var DAYS_IN_MONTH:Array = [
			31,
			28,
			31,
			30,
			31,
			30,
			31,
			31,
			30,
			31,
			30,
			31,
			30,
			31			
		];
   	}
}